package org.ramoths.netcom.outils;

import java.security.SecureRandom;

import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.MD5Digest;
import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.modes.CFBBlockCipher;
import org.bouncycastle.crypto.paddings.ISO10126d2Padding;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.crypto.params.ParametersWithRandom;

public class CipherAES
{
	private final PaddedBufferedBlockCipher aes;
	private final Digest md5;
	private final SecureRandom srand;
	private boolean occupe;
	
	public CipherAES(SecureRandom srand)
	{
		this.aes = new PaddedBufferedBlockCipher(
				new CFBBlockCipher(
						new AESEngine(),
						16*8
						),
				new ISO10126d2Padding()
				);
		this.md5 = new MD5Digest();
		this.srand = srand;
		this.occupe = false;
	}
	
	public byte[] crypter(byte[] msg, int debut, int taille, byte[] cle, long sequenceIV)
	{
		byte[] iv = new byte[16];
		byte[] r = null;
		int nb = 0;
		//
		md5.reset();
		md5.update(Outils.desLong(sequenceIV), 0, 8);
		md5.doFinal(iv, 0);
		//
		aes.reset();
		aes.init(
				true,
				new ParametersWithRandom(
						new ParametersWithIV(
								new KeyParameter(cle),
								iv
								),
								srand
						)
				);
		r = new byte[aes.getOutputSize(taille)];
		try
		{
			nb = aes.processBytes(msg, debut, taille, r, 0);
			nb += aes.doFinal(r, nb);
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
		//
		if (r.length != nb)
		{
			byte[] tmp = new byte[nb];
			System.arraycopy(r, 0, tmp, 0, tmp.length);
			r = tmp;
		}
		return r;
	}
	
	public byte[] decrypter(byte[] msg, int debut, int taille, byte[] cle, long sequenceIV)
	{
		byte[] iv = new byte[16];
		byte[] r = null;
		int nb = 0;
		//
		md5.reset();
		md5.update(Outils.desLong(sequenceIV), 0, 8);
		md5.doFinal(iv, 0);
		//
		aes.reset();
		aes.init(
				false,
				new ParametersWithRandom(
						new ParametersWithIV(
								new KeyParameter(cle),
								iv
								),
								srand
						)
				);
		r = new byte[aes.getOutputSize(taille)];
		try
		{
			nb = aes.processBytes(msg, debut, taille, r, 0);
			nb += aes.doFinal(r, nb);
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
		//
		if (r.length != nb)
		{
			byte[] tmp = new byte[nb];
			System.arraycopy(r, 0, tmp, 0, tmp.length);
			r = tmp;
		}
		return r;
	}
	
	public boolean isOccupe()
	{
		return occupe;
	}
	
	public void setOccupe(boolean occupe)
	{
		this.occupe = occupe;
	}
}
